package com.uinnova.product.eam.service.fx.impl;

import cn.hutool.core.collection.ListUtil;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.uinnova.product.eam.base.local.TaskFromWorkflowContext;
import com.uinnova.product.eam.base.local.TaskFromWorkflowContextValue;
import com.uinnova.product.eam.comm.exception.BusinessException;
import com.uinnova.product.eam.comm.model.es.EamCategory;
import com.uinnova.product.eam.comm.utils.CiUtil;
import com.uinnova.product.eam.db.bean.DiagramChangeData;
import com.uinnova.product.eam.model.bm.DiagramPrivateAndDesginData;
import com.uinnova.product.eam.model.bm.PushParams;
import com.uinnova.product.eam.model.constants.NoticeConstant;
import com.uinnova.product.eam.model.enums.AssetType;
import com.uinnova.product.eam.model.enums.CategoryTypeEnum;
import com.uinnova.product.eam.model.enums.ConflictEnum;
import com.uinnova.product.eam.model.vo.PushCheckVO;
import com.uinnova.product.eam.model.vo.SharePublishAssertMsgVo;
import com.uinnova.product.eam.service.DiagramProcessSvc;
import com.uinnova.product.eam.service.EamCategorySvc;
import com.uinnova.product.eam.service.EamDiagramRelationSysService;
import com.uinnova.product.eam.service.IEamNoticeService;
import com.uinnova.product.eam.service.bm.FlowModelMergeSvc;
import com.uinnova.product.eam.service.fx.CheckConflictSvc;
import com.uinnova.product.eam.service.fx.GeneralPushSvc;
import com.uinnova.product.eam.service.fx.ProcessCiRltSvc;
import com.uinnova.product.eam.service.fx.ProcessDiagramSvc;
import com.uinnova.product.eam.service.handler.PushFacadeService;
import com.uinnova.product.eam.service.impl.IamsCIDesignSvc;
import com.uinnova.product.vmdb.comm.model.ci.CCcCi;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uinnova.product.vmdb.provider.ci.bean.CiGroupPage;
import com.uinnova.project.base.diagram.comm.diagram.DiagramShareRecord;
import com.uinnova.project.base.diagram.comm.diagram.ESDiagramNodeQueryBean;
import com.uinnova.project.base.diagram.comm.model.ESDiagram;
import com.uinnova.project.base.diagram.comm.model.ESDiagramDTO;
import com.uinnova.project.base.diagram.comm.model.ESDiagramInfoDTO;
import com.uinnova.project.base.diagram.comm.model.ESDiagramNode;
import com.uinnova.project.db.eam.ESDiagramNodeDao;
import com.uinnova.project.service.eam.ESShareDiagramSvc;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.cmdb.base.ESCIRltInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.cmdb.query.ESCISearchBean;
import com.uino.bean.permission.base.SysUser;
import com.uino.bean.permission.business.UserInfo;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Slf4j
public class GeneralPushSvcImpl implements GeneralPushSvc {

    @Autowired
    ProcessDiagramSvc processDiagramSvc;

    @Autowired
    ProcessCiRltSvc processCiRltSvc;

    @Autowired
    PushFacadeService pushFacadeService;

    @Autowired
    ESDiagramNodeDao esDiagramNodeDao;

    @Autowired
    private IEamNoticeService eamNoticeService;

    @Autowired
    private IamsCIDesignSvc iamsCiDesignSvc;

    @Autowired
    private EamDiagramRelationSysService eamDiagramRelationSysService;

    @Autowired
    private EamCategorySvc categorySvc;

    @Autowired
    private CheckConflictSvc checkConflictSvc;

    @Autowired
    private FlowModelMergeSvc flowModelMergeSvc;

    @Autowired
    private DiagramProcessSvc diagramProcessSvc;

    @Autowired
    private IUserApiSvc userApiSvc;
    @Autowired
    private ESShareDiagramSvc shareDiagramSvc;

    /**
     * 通用发布校验步骤
     */
    private static final Integer PRIMARY_KEY_CHECK = 1;      // 主键冲突
    private static final Integer PRODUCT_NUM_CHECK = 2;      // 制品数量
    private static final Integer REQUIRED_FIELD_CHECK = 3;      // 必填项校验
    private static final Integer DIAGRAM_VERSION_CHECK = 4;      // 视图数据版本
    private static final Integer CI_VERSION_CHECK = 5;      // CI版本校验

    private static final Integer ARTIFACT_DIAGRAM = 2;  //制品视图

    @Override
    public String publishDiagram(String dEnergyId, String releaseDesc, Long dirId, String releaseDiagramId, Boolean needApprove, Boolean dealSameKey) {
        // 校验当前文件夹是否存在
//        if (!processDiagramSvc.checkDirExist(dirId, LibType.DESIGN)) {
//            throw new BinaryException("当前选择的文件目录已被管理员删除，请重新选择");
//        }
        List<ESDiagramDTO> esDiagramDTOS = processDiagramSvc.queryDiagramInfoByIds(Collections.singletonList(dEnergyId));
        ESDiagramInfoDTO diagram = esDiagramDTOS.get(0).getDiagram();
        // 鉴别一下普通视图和模型下的普通视图
        Long privateDirId = diagram.getDirId();
        EamCategory privateDirInfo = categorySvc.getById(privateDirId, LibType.PRIVATE);
        // 模型审批主版本暂时不接入
        if (!BinaryUtils.isEmpty(privateDirInfo) && privateDirInfo.getType().equals(CategoryTypeEnum.MODEL.val())) {
            needApprove = Boolean.FALSE;
        }

        if (needApprove) {
            // 非制品视图 不需要判断进行审批判断
            AssetType assetType = !BinaryUtils.isEmpty(privateDirInfo) && privateDirInfo.getType() == CategoryTypeEnum.MODEL.val() ? AssetType.MODEL : AssetType.DIAGRAM;
            diagramProcessSvc.submit(dEnergyId, dirId, releaseDesc, new ArrayList<>(), Boolean.FALSE, assetType);
            //若提交人不是视图/方案 创建人，创建人侧发送消息通知：您创建的 【视图/方案】 【视图/方案名称】 已由【提交人】提交审批
            sendShareSubmitIfNeed(diagram);
            //当前视图发布已开启流程 不做发布处理
            return "1";
        }

        //处理视图不走审批流场景（如果走审批流了，那么在发起流程的时候就会推消息）
        TaskFromWorkflowContextValue contextValue = TaskFromWorkflowContext.getContext();
        if (contextValue == null || Boolean.FALSE.equals(contextValue.getFromWorkflow())) {
            //若提交人不是视图/方案 创建人，创建人侧发送消息通知：您创建的 【视图/方案】 【视图/方案名称】 已由【提交人】提交审批
            sendShareSubmitIfNeed(diagram);
        }

        if (diagram.getIsOpen() == 1) {
            // 查询的列表有问题 原则上设计库的视图不能再发布
            log.info("###########当前单图发布的EID:【{}】为设计库数据，无法进行发布，直接返回ID", dEnergyId);
            //推送工作台-消息
            eamNoticeService.diagramUpdateMsgSave(Stream.of(dEnergyId).collect(Collectors.toList()));
            return dEnergyId;
        }
        if (!BinaryUtils.isEmpty(privateDirInfo) && privateDirInfo.getType() == 5) {
            // 模型下的普通视图
            flowModelMergeSvc.push(new ArrayList<>(), dEnergyId, releaseDesc, dirId);
            return "1";
        } else {
            String ownerCode = diagram.getOwnerCode();

            log.info("##########视图id:【{}】进入发布流程##########", dEnergyId);
            SysUser userInfoByOwnerCode = processCiRltSvc.getUserInfoByOwnerCode(ownerCode);
            // 获取私有库 / 设计库对应数据
            DiagramPrivateAndDesginData privateAndDesginDataByDEnergyId;
            if (!dealSameKey) {
                privateAndDesginDataByDEnergyId = processCiRltSvc.getPrivateAndDesginDataByDEnergyId(esDiagramDTOS, userInfoByOwnerCode);
            } else {
                privateAndDesginDataByDEnergyId = processCiRltSvc.getAndDealPrivateAndDesginDataByDEnergyId(esDiagramDTOS, userInfoByOwnerCode);
            }            // 获取当前视图的 CI 变更数据
            Map<String, List<DiagramChangeData>> changeCIDataByDEnergyId = processCiRltSvc.getChangeCIDataByDEnergyIds(privateAndDesginDataByDEnergyId);
            // 当前CI数据处理
            List<CcCiInfo> ccCiInfos = processCiRltSvc.dealPublishDiagramCI(changeCIDataByDEnergyId, ownerCode);
            // 当前关系数据 直接走新建覆盖
            List<ESCIRltInfo> esciRltInfos = processCiRltSvc.dealPublishDiagramRlt(privateAndDesginDataByDEnergyId, ccCiInfos);
            // 视图发布 以及 关联节点关系
            Map<String, Long> diagramMap = new HashMap<>();
            diagramMap.put(dEnergyId, dirId);

            Map<String, String> data = processDiagramSvc.dealReleaseDiagram(esDiagramDTOS, releaseDesc, diagramMap);
            // 发布视图的 node 与 link 绑定数据版本信息
            pushFacadeService.bindVersionNoByDiagramId(Collections.singletonList(data.get(dEnergyId)));
            //推送工作台-消息
            eamNoticeService.diagramUpdateMsgSave(Stream.of(dEnergyId).collect(Collectors.toList()));
            return data.get(dEnergyId);
        }
    }

    private void sendShareSubmitIfNeed(ESDiagramInfoDTO diagram) {
        //提交审批人是否当前用户
        String curLoginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        UserInfo userInfo = userApiSvc.getUserInfoByLoginCode(curLoginCode);
        if (curLoginCode.equals(diagram.getOwnerCode())) {
            return;
        }
        DiagramShareRecord shareRecord = shareDiagramSvc.queryShare(diagram.getId(), userInfo.getId());
        if (shareRecord == null) {
            return;
        }
        //获取当前协作者权限
        if (shareRecord.getPermission() == null || shareRecord.getPermission() != 4) {
            return;
        }
        //给视图创建人发送协作者提交审批消息：您创建的 【视图/方案】 【视图/方案名称】 已由【提交人】提交审批
        SharePublishAssertMsgVo sharePublishAssertMsgVo = new SharePublishAssertMsgVo();
        sharePublishAssertMsgVo.setAssertOwnerCode(diagram.getOwnerCode());
        sharePublishAssertMsgVo.setType(NoticeConstant.TAG_DIAGRAM);
        sharePublishAssertMsgVo.setAssertName(diagram.getName());
        sharePublishAssertMsgVo.setAssertId(diagram.getDEnergy());
        sharePublishAssertMsgVo.setShareUserId(userInfo.getId());
        sharePublishAssertMsgVo.setShareUserName(userInfo.getUserName());
        eamNoticeService.sharePublishAssertMsgSave(sharePublishAssertMsgVo);
    }

    @Override
    public String htPublishDiagram(String dEnergyId, String releaseDesc, Long dirId, String releaseDiagramId, Boolean isCustom) {
        // 校验当前文件夹是否存在
        if (dirId.longValue() != 0) {
            if (!processDiagramSvc.checkDirExist(dirId, LibType.DESIGN)) {
                throw new BinaryException("当前选择的文件目录已被管理员删除，请重新选择");
            }
        }
        List<ESDiagramDTO> esDiagramDTOS = processDiagramSvc.queryDiagramInfoByIds(Collections.singletonList(dEnergyId));
        if (esDiagramDTOS.get(0).getDiagram().getIsOpen() == 1) {
            // 查询的列表有问题 原则上设计库的视图不能再发布
            log.info("###########当前单图发布的EID:【{}】为设计库数据，无法进行发布，直接返回ID", dEnergyId);
            return dEnergyId;
        }
        String ownerCode = esDiagramDTOS.get(0).getDiagram().getOwnerCode();

        log.info("##########视图id:【{}】进入发布流程##########", dEnergyId);
        SysUser userInfoByOwnerCode = processCiRltSvc.getUserInfoByOwnerCode(ownerCode);
        // 获取私有库 / 设计库对应数据
        DiagramPrivateAndDesginData privateAndDesginDataByDEnergyId = processCiRltSvc.getPrivateAndDesginDataByDEnergyId(esDiagramDTOS, userInfoByOwnerCode, isCustom);
        // 获取当前视图的 CI 变更数据
        Map<String, List<DiagramChangeData>> changeCIDataByDEnergyId = processCiRltSvc.getChangeCIDataByDEnergyIds(privateAndDesginDataByDEnergyId);
        // 当前CI数据处理
        List<CcCiInfo> ccCiInfos = processCiRltSvc.dealHTPublishDiagramCI(changeCIDataByDEnergyId, ownerCode, isCustom);
        // 当前关系数据 直接走新建覆盖
        List<ESCIRltInfo> esciRltInfos = processCiRltSvc.dealPublishDiagramRlt(privateAndDesginDataByDEnergyId, ccCiInfos);
        // 视图发布 以及 关联节点关系
        Map<String, Long> diagramMap = new HashMap<>();
        diagramMap.put(dEnergyId, dirId);
        // 单图发布兼容业务组件发布逻辑 指定发布关联关系
        if (!BinaryUtils.isEmpty(releaseDiagramId)) {
            esDiagramDTOS.get(0).getDiagram().setReleaseDiagramId(releaseDiagramId);
        }
        Map<String, String> data = processDiagramSvc.dealReleaseDiagram(esDiagramDTOS, releaseDesc, diagramMap);
        // 发布视图的 node 与 link 绑定数据版本信息
        pushFacadeService.bindVersionNoByDiagramId(Collections.singletonList(data.get(dEnergyId)));
        return data.get(dEnergyId);
    }

    private Long handlerAppBuildDiagramPublish(ESDiagramInfoDTO diagram, Long dirId) {
        Integer diagramSubType = diagram.getDiagramSubType();
        if (diagramSubType == null) {
            throw new BusinessException("发布失败，获取视图信息错误!");
        }
        if (Objects.equals(diagramSubType, ARTIFACT_DIAGRAM)) {
            ESDiagram esDiagram = new ESDiagram();
            BeanUtils.copyProperties(diagram, esDiagram);
            eamDiagramRelationSysService.esDiagramSetRelationProperties(ListUtil.toList(esDiagram));
            if (!StringUtils.isEmpty(esDiagram.getCiCode())) {
                EamCategory eamCategory = categorySvc.selectByCiCode(null, esDiagram.getCiCode(), null, LibType.DESIGN);
                if (BinaryUtils.isEmpty(eamCategory)) {
                    ESCISearchBean bean = new ESCISearchBean();
                    CCcCi cdt = new CCcCi();
                    cdt.setCiCodeEqual(esDiagram.getCiCode());
                    bean.setCdt(cdt);
                    CiGroupPage ciGroupPage = iamsCiDesignSvc.queryPageBySearchBean(bean, false);
                    if (BinaryUtils.isEmpty(ciGroupPage) || CollectionUtils.isEmpty(ciGroupPage.getData())) {
                        throw new BusinessException("视图绑定的系统不存在");
                    }
                    CcCiInfo ciInfo = ciGroupPage.getData().get(0);
                    return newCreateDesignDir(ciInfo, dirId);
                }
            }
        }
        return null;
    }

    /**
     *  新表创建默认目录方法
     * @param ci
     * @param parentId
     * @return
     */
    private Long newCreateDesignDir(CcCiInfo ci, Long parentId) {
        EamCategory eamCategory = new EamCategory();
        eamCategory.setDirName(CiUtil.parseCiLabel(ci.getCi()));
        eamCategory.setCiCode(ci.getCi().getCiCode());
        eamCategory.setParentId(parentId);
        eamCategory.setType(CategoryTypeEnum.SYSTEM.val());
        return categorySvc.saveOrUpdate(eamCategory, LibType.DESIGN);
    }

    @Override
    public Map<String, String> batchPublishDiagram(List<String> diagramIds, Map<String, Long> puiblishDirSite) {
        List<Long> designCategorys = new ArrayList<>(puiblishDirSite.values());
        List<EamCategory> designCategoryList = categorySvc.getByIds(designCategorys, LibType.DESIGN);
        Map<Long, EamCategory> designCategoryMap = designCategoryList.stream().collect(Collectors.toMap(EamCategory::getId, e -> e, (k1, k2) -> k1));
        // 校验目录的合法性
        List<Long> dropDirIds = new ArrayList<>();
        for (Long designCategory : designCategorys) {
            if (!designCategoryMap.containsKey(designCategory)) {
                dropDirIds.add(designCategory);
            }
        }
        if (!BinaryUtils.isEmpty(dropDirIds)) {
            throw new BinaryException("视图发布的文件目录id【" + JSONObject.toJSONString(dropDirIds) + "】存在异常，请联系开发人员");
        }
        Map<String, String> res = new HashMap<>();

        // 根据ownerCode 先将整体数据做区分 K - 用户 V - 对应的视图集合
        List<ESDiagramDTO> esDiagramDTOS = processDiagramSvc.queryDiagramInfoByIds(diagramIds);
        Map<String, List<ESDiagramDTO>> userData = esDiagramDTOS.stream().collect(Collectors.groupingBy(e -> e.getDiagram().getOwnerCode()));       // 用户 和 用户对应的视图数据

        for (String userCode : userData.keySet()) {
            List<ESDiagramDTO> curESDiagramDTOS = userData.get(userCode);
            SysUser userInfoByOwnerCode = processCiRltSvc.getUserInfoByOwnerCode(userCode);
            // 获取该用户的 私有库 / 设计库 数据
            DiagramPrivateAndDesginData privateAndDesginDataByDEnergyId = processCiRltSvc.getPrivateAndDesginDataByDEnergyId(curESDiagramDTOS, userInfoByOwnerCode);
            // 批量获取当前所有视图的 CI 变更数据
            Map<String, List<DiagramChangeData>> changeCIDataByDEnergyId = processCiRltSvc.getChangeCIDataByDEnergyIds(privateAndDesginDataByDEnergyId);
            // #######进入发布数据流程########
            // 对当前用户名下的CI进行统一发布
            List<CcCiInfo> curUserCcCiInfos = processCiRltSvc.dealPublishDiagramCI(changeCIDataByDEnergyId, userCode);
            // 对当前用户名下的RLT进行统一发布 当前关系数据没有版本概念
            List<ESCIRltInfo> curUserESCiRltInfos = processCiRltSvc.dealPublishDiagramRlt(privateAndDesginDataByDEnergyId, curUserCcCiInfos);
            // 视图发布 以及 关联节点关系
            Map<String, String> publishData = processDiagramSvc.dealReleaseDiagram(curESDiagramDTOS, null, puiblishDirSite);
            res.putAll(publishData);
        }
        // 视图节点绑定版本号
        pushFacadeService.bindVersionNoByDiagramId(new ArrayList<>(res.values()));
        //推送工作台-消息
        eamNoticeService.diagramUpdateMsgSave(diagramIds);
        return res;
    }

    @Override
    public Map<Integer, Object> publishCheck(List<String> diagramIds) {
        /*
         *  通用视图发布前校验：（接口支持批量处理，支持多用户的数据同时校验）
         *  校验步骤：
         *      1.视图内CI的业务主键冲突情况
         *      2.关联制品的视图制品数量约束情况
         *      3.视图内CI必填项
         *      4.视图数据的版本
         *      5.视图内CI的版本
         * */

        if (CollectionUtils.isEmpty(diagramIds)) {
            return new HashMap<>();
        }

        Map<Integer, Object> result = new HashMap<>();

        // 根据ownerCode 先将整体数据做区分 K -> 用户 V -> 对应的视图集合
        List<ESDiagramDTO> allDiagramDTOS = processDiagramSvc.queryDiagramInfoByIds(diagramIds);
        // 过滤设计仓库的视图数据
        List<ESDiagramDTO> esDiagramDTOS = allDiagramDTOS.stream().filter(diagram -> diagram.getDiagram().getIsOpen() != 1).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(esDiagramDTOS)) {
            return new HashMap<>();
        }
        esDiagramDTOS.forEach(e -> {
            if (BinaryUtils.isEmpty(e.getDiagram().getViewType())) {
                // 未关联制品的数据暂时将viewType设置为0，方便后续校验分组
                e.getDiagram().setViewType("0");
            }
        });
        // 根据用户进行分组的数据
        Map<String, List<ESDiagramDTO>> userData = esDiagramDTOS.stream().collect(Collectors.groupingBy(e -> e.getDiagram().getOwnerCode()));
        // 根据用户信息 分组 私有库/设计库 数据
        Map<String, DiagramPrivateAndDesginData> privateAndDesginDataByUserCode = new HashMap<>();

        for (String userCode : userData.keySet()) {
            // 根据用户
            DiagramPrivateAndDesginData privateAndDesginDataByDEnergyId = processCiRltSvc.getPrivateAndDesginDataByDEnergyId(userData.get(userCode),
                    processCiRltSvc.getUserInfoByOwnerCode(userCode));
            privateAndDesginDataByUserCode.put(userCode, privateAndDesginDataByDEnergyId);
        }

        // 根据视图ID查询视图node节点
        List<Long> ids = esDiagramDTOS.stream().map(diagram -> diagram.getDiagram().getId()).collect(Collectors.toList());
        ESDiagramNodeQueryBean nodeQueryBean = new ESDiagramNodeQueryBean();
        nodeQueryBean.setDiagramIds(ids.toArray(new Long[ids.size()]));
        log.info("##################ids.size" + ids.size());
        List<ESDiagramNode> nodeList = esDiagramNodeDao.getListByCdt(nodeQueryBean);
        // 根据视图ID去做分离node数据
        Map<String, List<ESDiagramNode>> dEnergyAndNodeMap = nodeList.stream().collect(Collectors.groupingBy(e -> e.getdEnergy()));

        /*
         *  一.校验业务主键冲突情况 因为存在多用户数据的情况 后端暂时限制处理数据的规定：
         *   1.当前用户的视图可以直接处理
         *   2.非当前用户数据提示交给对应创建者处理（允许校验，有冲突的情况其他用户不能处理）
         *
         *   将视图数据先以用户做维度进行分组，查询出每个用户下需要发布的CI数据
         *   根据[业务主键] 及 [ciCode]为条件，对比当前视图上的CI数据，进行冲突校验
         * */

        // 当前返回值为用户层面的主键冲突数据
        Map<String, List<DiagramChangeData>> primaryKeyConflect = processCiRltSvc.checkPrimaryKeyConflict(userData, privateAndDesginDataByUserCode, Boolean.TRUE);

        for (String userCode : primaryKeyConflect.keySet()) {
            if (!CollectionUtils.isEmpty(primaryKeyConflect.get(userCode))) {
                // 主键校验未通过 这里将格式转换成以视图为维度的数据
                result.put(PRIMARY_KEY_CHECK, coverPrimaryConflentData(primaryKeyConflect, dEnergyAndNodeMap, userData));
                return result;
            }
        }

        /*
         *  二.校验视图关联制品数量限制，多用户可以并行处理 将所有视图使用到的制品统一查询处理
         *   当前维度不需要考虑视图用户 每一个制品下的所有视图 K -> 制品ID V -> 视图信息集合
         *
         *   将视图先以关联制品的ID为维度进行分组 之后开始进行校验
         *   获取制品的信息，提取出每个制品中的约束条件
         *   获取每张视图中的 {被当前关联制品约束的分类} 的 {CI的数量}
         *   拿到上面数据进行循环遍历，获得校验信息
         * */

        // 根据制品ID将视图数据进行分组
        Map<Long, List<ESDiagramDTO>> productNumData = esDiagramDTOS.stream().collect(Collectors.groupingBy(e -> Long.valueOf(e.getDiagram().getViewType())));       // 制品 和 制品的视图数据
        // 返回信息为每张视图对应的约束校验集合
        Map<String, List<String>> productCheckData = processCiRltSvc.checkCategoryEleNum(productNumData, dEnergyAndNodeMap);

        for (String dEnergy : productCheckData.keySet()) {
            if (!CollectionUtils.isEmpty(productCheckData.get(dEnergy))) {
                // 制品个数批量校验未通过
                result.put(PRODUCT_NUM_CHECK, productCheckData);
                return result;
            }
        }

        /*
         *  三.校验视图内CI必填项
         *
         *   将数据以用户为维度区分
         *   查询出用户名下的CI数据 校验每个CI的必填项信息
         *   查询出每张视图图内对应的node
         *   将上属数据进行重组 获取返回值
         *
         * */
        Map<String, Map<String, String>> requiredFieldCheckData = processCiRltSvc.checkRequiredFieldByIds(userData, privateAndDesginDataByUserCode, dEnergyAndNodeMap);

        for (String errMsg : requiredFieldCheckData.keySet()) {
            if (!MapUtils.isEmpty(requiredFieldCheckData.get(errMsg))) {
                // CI必填项批量校验未通过
                result.put(REQUIRED_FIELD_CHECK, requiredFieldCheckData);
                return result;
            }
        }

        /*
         *  四.校验视图本身版本 (以视图为维度进行校验)
         *
         * */
        Map<String, Boolean> diagramVersionCheckData = processDiagramSvc.checkDiagramVersionByIds(esDiagramDTOS);

        for (String diagramId : diagramVersionCheckData.keySet()) {
            if (diagramVersionCheckData.get(diagramId)) {
                // 视图版本批量校验未通过
                result.put(DIAGRAM_VERSION_CHECK, diagramVersionCheckData);
                return result;
            }
        }

        /*
         *  五.校验视图CI版本 (需要以用户为维度进行数据校验)
         *
         * */
        Map<String, List<DiagramChangeData>> userConflectData = processCiRltSvc.checkCIVersionByIds(userData, privateAndDesginDataByUserCode);     // 获取用户名下的冲突数据
        Map<String, Boolean> ciVersionCheckData = this.coverDiagramConflectData(userConflectData, userData, dEnergyAndNodeMap);

        for (String diagramId : ciVersionCheckData.keySet()) {
            if (ciVersionCheckData.get(diagramId)) {
                // 视图版本批量校验未通过
                result.put(CI_VERSION_CHECK, ciVersionCheckData);
                return result;
            }
        }
        // 返回空map为通过校验流程
        return result;
    }

    @Override
    public Map<Integer, Object> pushCkeck(List<Long> dirIds, List<String> diagramIds) {
        /*
         *  模型及模型视图发布前校验：（接口支持批量处理，支持多用户的数据同时校验）
         *  校验步骤：
         *      1.制品数量完整性校验 --》 强制
         *      2.视图内CI必填项  --》 强制
         *      3.模型目录发布上级完整性校验 --》 强制
         *      4.单图发布校验模型视图所在的仓库目录存在 --》 强制
         *      5.视图版本信息校验 --》 提示
         *      6.业务架构模型树配置完整性校验 --》 提示
         *
         *  普通视图发布前校验：（接口支持批量处理，支持多用户的数据同时校验）
         *  校验步骤：
         *
         *      1.关联制品的视图制品数量约束情况  --》 强制
         *      2.视图内CI必填项  --》 强制
         *      3.视图内CI的业务主键冲突情况  --》 强制
         *      4.视图数据的版本  --》 提示
         *      5.视图内CI的版本  --》 提示
         *
         *  提示校验前端弹窗提示，用户允许强制发布
         *  强制校验前端弹窗，需要用户手动解决校验的冲突信息
         * */

        Map<Integer, Object> result = new HashMap<>();
        try {
            //防止创建对象快速点击审批，对象未落到画布查询不到问题
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        PushParams pushParams = generateParams(dirIds, diagramIds);

        List<PushCheckVO> productNumConflict = checkConflictSvc.checkProductNum(pushParams);
        if (CollectionUtils.isNotEmpty(productNumConflict)) {
            result.put(ConflictEnum.PRODUCT_NUM_CHECK.getConflictType(), productNumConflict);
            return result;
        }

        List<PushCheckVO> requiredFieldConflict = checkConflictSvc.checkRequiredField(pushParams);
        if (CollectionUtils.isNotEmpty(requiredFieldConflict)) {
            result.put(ConflictEnum.REQUIRED_FIELD_CHECK.getConflictType(), requiredFieldConflict);
            return result;
        }

        List<PushCheckVO> primaryKeyConflict = checkConflictSvc.checkPrimaryKey(pushParams);
        if (CollectionUtils.isNotEmpty(primaryKeyConflict)) {
            result.put(ConflictEnum.PRIMARY_KEY_CHECK.getConflictType(), primaryKeyConflict);
            return result;
        }

//        Map<String, Object> ciVersionConflect = checkConflictSvc.checkCIVersion(pushParams);

        // 暂时不需要这个校验
        List<PushCheckVO> modelPlvlExistConflect = checkConflictSvc.checkModelPlvlExist(pushParams);

        List<PushCheckVO> modelDiagramLocExistConflect = checkConflictSvc.checkModelDiagramLocExist(pushParams);
        if (CollectionUtils.isNotEmpty(modelDiagramLocExistConflect)) {
            result.put(ConflictEnum.MODEL_DIAGRAM_LOCATION_CHECK.getConflictType(), modelDiagramLocExistConflect);
            return result;
        }

        List<PushCheckVO> pushLocConflect = checkConflictSvc.checkPushLocation(pushParams);
        if (CollectionUtils.isNotEmpty(pushLocConflect)) {
            result.put(ConflictEnum.LOCATION_RIGTH_CHECK.getConflictType(), pushLocConflect);
            return result;
        }

        List<PushCheckVO> modelHierarchyCompleteConflect = checkConflictSvc.checkModelHierarchyComplete(pushParams);
        if (CollectionUtils.isNotEmpty(modelHierarchyCompleteConflect)) {
            result.put(ConflictEnum.MODEL_HIERARCHY_COMPLETE_CHECK.getConflictType(), modelHierarchyCompleteConflect);
        }

        List<PushCheckVO> diagramVersionConflect = checkConflictSvc.checkDiagramVersion(pushParams);
        if (CollectionUtils.isNotEmpty(diagramVersionConflect)) {
            result.put(ConflictEnum.DIAGRAM_VERSION_CHECK.getConflictType(), diagramVersionConflect);
        }

        checkConflictSvc.checkProcessStartUserIsCurUserCaseUnPassSubmit(pushParams);

        return result;
    }

    /**
     *  根据目录及视图参数生成发布校验参数
     * @param dirIds
     * @param diagramIds
     * @return
     */
    public PushParams generateParams(List<Long> dirIds, List<String> diagramIds) {
        PushParams pushParams = new PushParams();
        // id
        List<String> commonDiagramIds = new ArrayList<>();
        List<String> modelDiagramIds = new ArrayList<>();
        List<Long> modelDirIds = new ArrayList<>();
        // info
        List<ESDiagramDTO> commonDiagramList = new ArrayList<>();
        List<ESDiagramDTO> modelDiagramList = new ArrayList<>();
        List<EamCategory> modelCategoryList = new ArrayList<>();
        List<ESDiagramDTO> allDiagramList = new ArrayList<>();
        // map
        Map<String, List<ESDiagramDTO>> commonDiagramMap = new HashMap<>();
        Map<String, List<ESDiagramDTO>> modelDiagramMap = new HashMap<>();
        Map<String, List<EamCategory>> modelCategoryMap = new HashMap<>();
        Map<String, List<ESDiagramDTO>> allDiagramMap = new HashMap<>();

        if (!CollectionUtils.isEmpty(diagramIds)) {
            // 传参视图ID 两种视图都有可能
            List<ESDiagramDTO> processDiagramList = processDiagramSvc.queryDiagramInfoByIds(diagramIds);
            processDiagramList = processDiagramList.stream().filter(e->e.getDiagram().getIsOpen()==0).collect(Collectors.toList());

            Set<Long> localDirIds = new HashSet<>();
            for (ESDiagramDTO esDiagram : processDiagramList) {
                localDirIds.add(esDiagram.getDiagram().getDirId());
            }
            List<EamCategory> localDirList = categorySvc.getByIds(new ArrayList<>(localDirIds), LibType.PRIVATE);
            for (EamCategory localDir : localDirList) {
                if (!BinaryUtils.isEmpty(localDir.getModelId()) && localDir.getType() != 4) {
                    modelDirIds.add(localDir.getId());
                    modelCategoryList.add(localDir);
                }
            }
            if (!CollectionUtils.isEmpty(modelCategoryList)) {
                modelCategoryMap = modelCategoryList.stream().collect(Collectors.groupingBy(item -> item.getOwnerCode()));
            }

            for (ESDiagramDTO processDiagram : processDiagramList) {
                String energyId = processDiagram.getDiagram().getDEnergy();
                if (modelDirIds.contains(processDiagram.getDiagram().getDirId())) {
                    modelDiagramIds.add(energyId);
                    modelDiagramList.add(processDiagram);
                } else {
                    commonDiagramIds.add(energyId);
                    commonDiagramList.add(processDiagram);
                }
                allDiagramList.add(processDiagram);
            }

            if (!CollectionUtils.isEmpty(modelDiagramList)) {
                modelDiagramMap = modelDiagramList.stream().collect(Collectors.groupingBy(item -> item.getDiagram().getOwnerCode()));
            }
            if (!CollectionUtils.isEmpty(commonDiagramList)) {
                commonDiagramMap = commonDiagramList.stream().collect(Collectors.groupingBy(item -> item.getDiagram().getOwnerCode()));
            }
            if (!CollectionUtils.isEmpty(allDiagramList)) {
                allDiagramMap = allDiagramList.stream().collect(Collectors.groupingBy(item -> item.getDiagram().getOwnerCode()));
            }

            // 组装
            pushParams.setModelDirIds(modelDirIds).setCommonDiagramIds(commonDiagramIds).setModelDiagramIds(modelDiagramIds).
                    setModelCategoryList(modelCategoryList).setCommonDiagramList(commonDiagramList).setModelDiagramList(modelDiagramList).
                    setModelCategoryMap(modelCategoryMap).setCommonDiagramMap(commonDiagramMap).setModelDiagramMap(modelDiagramMap).
                    setAllProcessDiagramIds(diagramIds).setAllProcessDiagramInfo(allDiagramList).setAllProcessDiagramMap(allDiagramMap).
                    setIsModelTree(Boolean.FALSE);
        } else {
            // 传参仅有目录信息代表模型发布 且 仅代表用户在我的空间手动选择
            List<EamCategory> localDirList = categorySvc.getByIds(dirIds, LibType.PRIVATE);
            modelDiagramList = processDiagramSvc.queryDiagramInfoByDirIds(dirIds);

            for (ESDiagramDTO modelDiagram : modelDiagramList) {
                modelDiagramIds.add(modelDiagram.getDiagram().getDEnergy());
            }

            if (!CollectionUtils.isEmpty(localDirList)) {
                modelCategoryMap = localDirList.stream().collect(Collectors.groupingBy(item -> item.getOwnerCode()));
            }
            if (!CollectionUtils.isEmpty(modelDiagramList)) {
                modelDiagramMap = modelDiagramList.stream().collect(Collectors.groupingBy(item -> item.getDiagram().getOwnerCode()));
            }
            pushParams.setModelDirIds(dirIds).setModelDiagramIds(modelDiagramIds).
                    setModelCategoryList(localDirList).setModelDiagramList(modelDiagramList).
                    setModelCategoryMap(modelCategoryMap).setModelDiagramMap(modelDiagramMap).
                    setAllProcessDiagramIds(modelDiagramIds).setAllProcessDiagramInfo(modelDiagramList).setAllProcessDiagramMap(modelDiagramMap).
                    setIsModelTree(Boolean.TRUE);
        }
        return pushParams;
    }

    /**
     *  批量校验 返回值格式转换 由用户对应数据 转成 视图ID对应数据
     * @param primaryKeyConflect 转化之前的冲突校验结果（由用户对应数据）
     * @param idAndNodeInfo 视图ID -》 当前视图的节点信息
     * @param userData 用户 —》 用户的视图列表
     * @return 视图ID对应数据
     */
    private Map<String, List<DiagramChangeData>> coverPrimaryConflentData(Map<String, List<DiagramChangeData>> primaryKeyConflect,
                                                                          Map<String, List<ESDiagramNode>> idAndNodeInfo,
                                                                          Map<String, List<ESDiagramDTO>> userData) {
        Map<String, List<DiagramChangeData>> data =  new HashMap<>();

        for (String user : userData.keySet()) {         //最外层循环用户名
            for (ESDiagramDTO esDiagramDTO : userData.get(user)) {          // 遍历用户名下视图列表
                // 获取当前视图的node信息 取其中的ciCode字段与冲突数据中的私有库数据进行比对
                List<ESDiagramNode> esDiagramNodes = idAndNodeInfo.get(esDiagramDTO.getDiagram().getDEnergy());
                List<String> ciCodes = esDiagramNodes.stream().map(ESDiagramNode::getCiCode).collect(Collectors.toList());
                if (!BinaryUtils.isEmpty(primaryKeyConflect.get(user))) {            // 当前视图所属用户名下存在冲突数据

                    List<String> conflentCiCodes = new ArrayList<>();
                    List<DiagramChangeData> conflectData = primaryKeyConflect.get(user);
                    for (DiagramChangeData diagramChangeData : conflectData) {
                        conflentCiCodes.add(diagramChangeData.getPrivateCiInfo().getCi().getCiCode());
                    }
                    ciCodes.retainAll(conflentCiCodes);     // 取交集 结果为当前视图的冲突节点

                    if (!CollectionUtils.isEmpty(ciCodes)) {            // 当前视图的ci存在冲突数据
                        List<DiagramChangeData> conflentData = new ArrayList<>();           // 塞入每张视图对应的冲突数据
                        for (DiagramChangeData diagramChangeData : conflectData) {
                            if (ciCodes.contains(diagramChangeData.getPrivateCiInfo().getCi().getCiCode())) {
                                conflentData.add(diagramChangeData);
                            }
                        }
                        data.put(esDiagramDTO.getDiagram().getDEnergy(), conflentData);
                    }
                }
            }
        }

        return data;
    }

    /**
     *  将CI版本校验数据由用户维度转换成视图维度
     * @param userConflectData 用户 -》 版本冲突的CI
     * @param userData 用户 -》 用户名下的视图信息
     * @param idAndNodeInfo 视图ID -》 视图上的node信息
     * @return
     */
    private Map<String, Boolean> coverDiagramConflectData(Map<String, List<DiagramChangeData>> userConflectData,
                                                         Map<String, List<ESDiagramDTO>> userData,
                                                         Map<String, List<ESDiagramNode>> idAndNodeInfo) {

        Map<String, Boolean> diagramAndCIConflectMap = new HashMap<>();     // 整体调整之后的返回值

        for (String userCode : userData.keySet()) {
            for (ESDiagramDTO esDiagramDTO : userData.get(userCode)) {
                // 默认没有冲突
                Boolean CIVersionConflect = false;
                if (!CollectionUtils.isEmpty(idAndNodeInfo.get(esDiagramDTO.getDiagram().getDEnergy()))) {
                    // 获取当前视图内的节点信息
                    List<String> ciCodes = idAndNodeInfo.get(esDiagramDTO.getDiagram().getDEnergy()).stream().map(ESDiagramNode::getCiCode).collect(Collectors.toList());
                    // 获取当前用户整体的CI版本冲突数据
                    List<DiagramChangeData> diagramChangeData = userConflectData.get(userCode);
                    for (DiagramChangeData changeData : diagramChangeData) {        // 遍历冲突数据 在视图上匹配
                        if (ciCodes.contains(changeData.getPrivateCiInfo().getCi().getCiCode())) {
                            CIVersionConflect = true;
                        }
                    }
                }
                diagramAndCIConflectMap.put(esDiagramDTO.getDiagram().getDEnergy(), CIVersionConflect);
            }
        }
        return diagramAndCIConflectMap;
    }

}
